package com.kamistoat.ruoyi.ruoyigateway.config;

import com.kamistoat.ruoyi.ruoyigateway.handler.ValidateCodeHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

/**
 * 响应式编程框架中的路由配置类。
 * 该类和Gateway毫无关系，是响应式编程的内容。理解其原理后不仅可以在Gateway中使用，也可以在其他模块中甚至将所有的业务层都更改为响应式编程。
 *
 * 另外，这里需要和在yaml文件中配置的 routes 区分开。
 * 这里相当于是在对任意的路径进行 @RequestMapping，而后者则是在进行服务转发!!!!
 *
 */
@Configuration
public class RouterFunctionConfiguration {
    @Autowired
    ValidateCodeHandler validateCodeHandler;

    /**
     * 设置特定的路由断言和handler。
     * RouterFunction同样是web响应式编程中的内容。
     * RouterFunction是响应式编程提供的两种框架之一。另一种则是直接将普通的@Controller/@Service接口的返回内容，由原先的pojo改为 Mono<pojo>.
     * RouterFunction提供一套函数式风格的API，用于创建 Router 和 Handler对象(同样在该模块中也有体现)。
     * 其中，可以简单将 Handler理解为 @Controller， 将Router理解为 @RequestMapping
     * <p>
     * 可以写无数个 RouterFunction
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction() {
        // RouterFunction是个接口不能被new出来，好像只能通过 RouterFunctions抽象类的方法来构建。
        // route(RequestPredicate predicate, HandlerFunction<T> handlerFunction) -- 首参为 请求断言(在商城项目中是在yaml中手写断言)，二参为处理请求的handler
        RouterFunction<ServerResponse> routerFunction = RouterFunctions.route(
                // 对来自 "/code"路径的 GET类型的 MediaType.TEXT_PLAIN 的 Request
                RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                // 交给 validateCodeHandler 处理。注意ValidateCodeHandler类中的 handler方法的唯一入参，将直接映射到这里断言匹配上的 Request
                validateCodeHandler);

        // 如果还有其他的路由规则，routerFunction.andRoute(RequestPredicate predicate, HandlerFunction<T> handlerFunction) 写新的路由规则即可
        // routerFunction.andRoute();
        return routerFunction;
    }

    /**
     * 仍然是 Router。就像传统架构中写很多个 @RequestMapping一样，Router中同样可以写很多个 route来进行绑定。
     * 理解这种思路之后，就可以在任何web模块中使用响应式编程，而不仅仅是在Gateway模块中。
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunctionAnother() {
        // 为Router绑定三个handle
        // 注意下面的三种写法实现的功能是一样的。
        RouterFunction<ServerResponse> routerFunction = RouterFunctions
                .route(
                        RequestPredicates.GET("/handle_1").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),
                        validateCodeHandler::handle_1)
                .andRoute(
                        RequestPredicates.GET("/handle_2/{id}").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),
                        serverRequest -> validateCodeHandler.handle_2(serverRequest))
                .andRoute(
                        RequestPredicates.POST("/handle_3").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),
                        serverRequest -> {
                            return validateCodeHandler.handle_3(serverRequest);
                        });

        return routerFunction;
    }
}
